
interface DocItem {
    id: string | number;
    type: 'text';
    text?: string;
    plainText?: string;
    textStyleMap?: {
        [textIndex: string]: {
            text: string;
            [prop: string]: string | number | boolean;
        };
    };
}

interface SpeciesInfo {
    species_c: string
    genus: string
    canorical_me: string
    //....
}

const updateDocItemPlainText = (docItem: DocItem) => {
    const { text, textStyleMap } = docItem;
    let updatedPlainText = text;
    Object.entries(textStyleMap).forEach(([key, value]) => {
        updatedPlainText = updatedPlainText.replace(key, value.text);
    });
    docItem.plainText = updatedPlainText;
    return docItem;
}

export const fillLatinNameUtil = (docItemList: DocItem[], speciesInfoList: SpeciesInfo[]) => {
    let speciesAppearance = {};
    let genusAppearance = {};
    let textStyleMapIndex = 5000;
    const speciesOrderMap = new Map();
    speciesInfoList.forEach((item, index) => {
        let docItemIndex = -1;
        let docItemTextIndexOf = -1;
        const findIndex = docItemList.findIndex(docItem => docItem.plainText && docItem.plainText.indexOf(item.species_c) !== -1);
        if (findIndex != -1) {
            docItemIndex = findIndex;
            docItemTextIndexOf = docItemList[findIndex].plainText.indexOf(item.species_c);
        }
        speciesOrderMap.set(item.species_c, { info: item, docItemIndex, docItemTextIndexOf })
    });
    const speciesOrderList = Array.from(speciesOrderMap.values());
    speciesOrderList.sort((a, b) => {
        if (a.docItemIndex !== b.docItemIndex) {
            return a.docItemIndex - b.docItemIndex;
        } else {
            return a.docItemTextIndexOf - b.docItemTextIndexOf;
        }
    });
    const speciesInfoListSorted = speciesOrderList.map(ele => ele.info);
    docItemList.forEach(docItem => {
        if (!docItem.textStyleMap) {
            docItem.textStyleMap = {};
        }
        let needToUpdatePlainText = false;
        speciesInfoListSorted.forEach(({ genus, canorical_me, species_c }) => {
            let regex = new RegExp(`${species_c}(\\s*\\(.*?\\))?(?!\\s*\\()`, "g");
            let match = null;
            while ((match = regex.exec(docItem.text)) !== null) {
                if (speciesAppearance[species_c]) continue;
                const isGenusFirstAppearance = genusAppearance[genus] === undefined;
                genusAppearance[genus] = false;
                speciesAppearance[species_c] = true;

                const placeholder = `$$[${textStyleMapIndex}]`;
                let latinName = isGenusFirstAppearance ? canorical_me : `${genus[0]}. ${canorical_me.split(" ")[1]}`;
                if (isGenusFirstAppearance) {
                    let replacementText = `${species_c} (${placeholder})`;
                    docItem.text = docItem.text.substring(0, match.index) + replacementText + docItem.text.substring(match.index + match[0].length);
                    docItem.textStyleMap[placeholder] = {
                        text: latinName,
                        italic: isGenusFirstAppearance,
                    };
                } else {
                    let latinNameBefore = `${genus[0]}. `;
                    let latinNameAfter = `${canorical_me.split(" ")[1]}`
                    textStyleMapIndex++; 
                    const afterPlaceholder = `$$[${textStyleMapIndex}]`;
                    docItem.textStyleMap[placeholder] = {
                        text: latinNameBefore,
                        italic: isGenusFirstAppearance
                    };
                    docItem.textStyleMap[afterPlaceholder] = {
                        text: latinNameAfter,
                        italic: true,
                    };
                    let replacementText = `${species_c} (${placeholder}${afterPlaceholder})`;
                    docItem.text = docItem.text.substring(0, match.index) + replacementText + docItem.text.substring(match.index + match[0].length);
                }
                needToUpdatePlainText = true;
                textStyleMapIndex++;
            }
        });
        if (needToUpdatePlainText) {
            docItem = updateDocItemPlainText(docItem)
        }
    });
    return docItemList;
}